/*
 * SNSRC1.c
 *
 *  Created on: 07/02/2013
 *      Author: RIchard
 */


/* ---> Turn sensor on ---> Settle ---> Start measure (sample count) --->
 * Wait for callback ---> Get sample data ---> Filter ---> Done
 */
#include <string.h>
#include "SNSRC1.h"
#include "../../../cdef.h"
#include "../../../sensor.h"

#include "../PRES/PRESC1.h"
#include "../LGHT/LGHTC1.h"

typedef enum
{
   SNSR_nenState_Idle            = 0,     /* Sensor is not doing anything */
   SNSR_nenState_PowerOn         = 1,     /* Powering ON, waiting for power to settle */
   SNSR_nenState_StartMeasure    = 2,     /* Call to start measure */
   SNSR_nenState_WaitingForData  = 3,     /* Waiting for measurement to finish */
   SNSR_nenState_Filter          = 4      /* Filter data and finish */
} SNSR_nenSensorState;

typedef struct
{
   void (*pfControlPower)(DIO_tenLogicLevel enState);
   uint16 u16SettlingTime;
   bool (*pfStartMeasure)(void);
   void (*pfFilterData)(void);
} SNSR_tstSensorList;

#if 0
static const SNSR_tstSensorList SNSR_stSensorList[ SNSR_nenNumberOfSensors ] =
{
   /*                              Power                   Settling Time  Measure                           Samples     Get Data                    Filter Function      */
   /* SNSR_nenBattery         */ { NULL,                   0,             &BATT_boStartMeasure,             8,          &BATT_boGetVBAT,            &FILTER_vMean     },
   /* SNSR_nenChipTemperature */ { NULL,                   0,             &TEMP_boStartMeasure,             8,          &TEMP_boGetChipTemp,        &FILTER_vMedian   },
   /* SNSR_nenTankPressure    */ { &PRES_vSetPower,        1000,          &PRES_boStartMeasure,             128,        &PRES_boGetTankPressue,     &FILTER_vMedian   },
   /* SNSR_nenLight           */ { &LGHT_vSetPower,        50,            &LGHT_boStartMeasure,             64,         &LGHT_boGetLightLevel,      &FILTER_vMedian   },
   /* SNSR_nenHumidity        */ { &HUM_vSetPower,         500,           &HUM_boStartMeasure,              64,         &HUM_boGetHumidity,         &FILTER_vMedian   },
   /* SNSR_nenBarometer       */ { &BMP085_vSetPower,      0,             &BMP085_boStartBarometerMeasure,  8,          &BMP085_boGetBarometer,     &FILTER_vMedian   },
   /* SNSR_nenAmbTemp         */ { &BMP085_vSetPower,      0,             &BMP085_boStartTempMeasure,       8,          &BMP085_boGetTemperature,   &FILTER_vMedian   },
   /* SNSR_nenAltitude        */ { &BMP085_vSetPower,      0,             &BMP085_boStartAltitudeMeasure,   8,          &BMP085_boGetAltitude,      &FILTER_vMedian   }
};
#else
static const SNSR_tstSensorList SNSR_stSensorList[ SNSR_nenNumberOfSensors ] =
{
   /*                                Power            Settling Time  Measure                 Filter Function      */
   /* SNSR_nenBattery         */ //{ NULL,            0,             NULL,                   NULL                  },
   /* SNSR_nenChipTemperature */ //{ NULL,            0,             NULL,                   NULL                  },
   /* SNSR_nenTankPressure    */ { &PRES_vSetPower,   1000,          &PRES_boStartMeasure,   PRES_vFilter          },
   /* SNSR_nenLight           */ { &LGHT_vSetPower,   100,           &LGHT_boStartMeasure,   LGHT_vFilter          },
   /* SNSR_nenHumidity        */ //{ NULL,            0,             NULL,                   NULL                  },
   /* SNSR_nenBarometer       */ //{ NULL,            0,             NULL,                   NULL                  },
   /* SNSR_nenAmbTemp         */ //{ NULL,            0,             NULL,                   NULL                  },
   /* SNSR_nenAltitude        */ //{ NULL,            0,             NULL,                   NULL                  }
};
#endif

/* Sample times - In minutes */
/* Temp in ROM for now, read from EEPROM later */
static const uint8 SNSR_cau8SampleTime[ SNSR_nenNumberOfSensors ] =
{
   /* SNSR_nenBattery         */    //1,
   /* SNSR_nenChipTemperature */    //5,
   /* SNSR_nenTankPressure    */    5,
   /* SNSR_nenLight           */    1,
   /* SNSR_nenHumidity        */    //5,
   /* SNSR_nenBarometer       */    //5,
   /* SNSR_nenAmbTemp         */    //5,
   /* SNSR_nenAltitude        */    //5
};

typedef struct
{
   SNSR_nenSensorState  enState;
   uint16               u16SampleTime;
} SNSR_tstSensorInfo;

static void SNSR__vProcessCurrentSensorActionTimerCallback( SWTIM_tstTimer *pstTimer );
static void SNSR__vProcessSensorPeriod( void );
static void SNSR__vProcessCurrentSensorAction( void );

/* Current active sensor */
static SNSR_nenSensorList  SNSR__enSensor;
/* Global minute counter */
static uint16              SNSR__u16MinuteCount;
/* Sensor data */
static SNSR_tstSensorInfo  SNSR__stSensorInfo[ SNSR_nenNumberOfSensors ];
/* Local copy of sensor sample times - Copied from EEPROM on reset */
static uint8               SNSR__au8SampleTime[ SNSR_nenNumberOfSensors ];

/* Called from the SWTIMER timeout callback */
static void SNSR__vProcessCurrentSensorActionTimerCallback( SWTIM_tstTimer *pstTimer )
{
   (void)pstTimer;
   SNSR__vProcessCurrentSensorAction();
}

static void SNSR__vProcessSensorPeriod( void )
{
   SNSR_nenSensorList enSensor;

   for( enSensor = (SNSR_nenSensorList)( SNSR_nenNumberOfSensors - 1 ); enSensor >= SNSR_nenFirstSensor; enSensor-- )
   {
      /* 1st time run, u16MinuteCount will be 0, u16SampleTime will be 0 - below will pass */
      if( SNSR__u16MinuteCount == SNSR__stSensorInfo[ enSensor ].u16SampleTime )
      {
         SNSR__stSensorInfo[ enSensor ].u16SampleTime += SNSR__au8SampleTime[ enSensor ];
         if( APP_stSystemFlags.unFlags.Bits.biLowBattery != True )
         {
            SNSR__stSensorInfo[ enSensor ].enState = SNSR_nenState_PowerOn;
         }
      }
   }
}

/* State machine allows for sleeping in between states
 * and co-operative multitasking */
static void SNSR__vProcessCurrentSensorAction( void )
{
   /* Local timer instance - made static - cannot be placed on stack */
   static SWTIM_tstTimer SNSR__stTimeoutTimer;

   switch( SNSR__stSensorInfo[ SNSR__enSensor ].enState )
   {
      case SNSR_nenState_Idle:
         SNSR__enSensor++;
         if( SNSR__enSensor < SNSR_nenNumberOfSensors )
         {
            APP_unRequests.F.biSensorReadRequest = 1;
         }
         else
         {
            /* No more sensors to process */
            SNSR__enSensor = SNSR_nenFirstSensor;
            /* Release the APP request - go back to sleep */
            APP_unRequests.F.biSensorReadRequest = 0;
         }
         break;

      case SNSR_nenState_PowerOn:
         if( SNSR_stSensorList[ SNSR__enSensor ].pfControlPower != NULL )
         {
            SNSR_stSensorList[ SNSR__enSensor ].pfControlPower( tHi );

            SNSR__stTimeoutTimer.interval = SNSR_stSensorList[ SNSR__enSensor ].u16SettlingTime;
            SNSR__stTimeoutTimer.mode = SWTIM_nenOneShotMode;
            SNSR__stTimeoutTimer.handler = &SNSR__vProcessCurrentSensorActionTimerCallback;
            SWTIM_vTimerStart( &SNSR__stTimeoutTimer );

            /* Go back to sleep and let the timer interrupt run this function again */
            APP_unRequests.F.biSensorReadRequest = 0;
         }
         else
         {
            /* Keep awake so the main loop can run the start measure routine */
            APP_unRequests.F.biSensorReadRequest = 1;
         }

         SNSR__stSensorInfo[ SNSR__enSensor ].enState = SNSR_nenState_StartMeasure;
         break;

      case SNSR_nenState_StartMeasure:
         if( SNSR_stSensorList[ SNSR__enSensor ].pfStartMeasure != NULL )
         {
            if( ( SNSR_stSensorList[ SNSR__enSensor ].pfStartMeasure() ) == True )
            {
               SNSR__stSensorInfo[ SNSR__enSensor ].enState = SNSR_nenState_WaitingForData;
            }
            else
            {
               SNSR__stSensorInfo[ SNSR__enSensor ].enState = SNSR_nenState_Idle;
            }
         }
         else
         {
            SNSR__stSensorInfo[ SNSR__enSensor ].enState = SNSR_nenState_Idle;
         }

         /* Turn the power off */
         if( SNSR__stSensorInfo[ SNSR__enSensor ].enState == SNSR_nenState_Idle )
         {
            if( SNSR_stSensorList[ SNSR__enSensor ].pfControlPower != NULL )
            {
               SNSR_stSensorList[ SNSR__enSensor ].pfControlPower( tLo );
            }

            /* Keep awake to allow the next sensor to run */
            APP_unRequests.F.biSensorReadRequest = 1;
         }
         else
         {
            /* Go back to sleep - Wait for sensor finish measurement interrupt */
            APP_unRequests.F.biSensorReadRequest = 0;
         }

         break;

      case SNSR_nenState_WaitingForData:
         /* If sensor has finished it will re-activate the APP request and re-run this function */

         /* Turn the power off */
         if( SNSR_stSensorList[ SNSR__enSensor ].pfControlPower != NULL )
         {
            SNSR_stSensorList[ SNSR__enSensor ].pfControlPower( tLo );
         }

         SNSR__stSensorInfo[ SNSR__enSensor ].enState = SNSR_nenState_Filter;

         /*
          * Do nothing with APP_unRequests.F.biSensorReadRequest, it will remain True.
          * This is required to allow the next sensor to run
          */
         break;

      case SNSR_nenState_Filter:
         /* Pass the data through a filter */
         if( SNSR_stSensorList[ SNSR__enSensor ].pfFilterData != NULL )
         {
            SNSR_stSensorList[ SNSR__enSensor ].pfFilterData();
         }
         /* Publish data back to the individual sensor module for processing */

         /* Finished. Set this sensor back to Idle - will process next period time */
         SNSR__stSensorInfo[ SNSR__enSensor ].enState = SNSR_nenState_Idle;
         break;

      default:
         break;
   }
}

void SNSR_vReset( void )
{
   memset( (void*)&SNSR__stSensorInfo, 0, sizeof(SNSR__stSensorInfo) );
   memcpy( (void*)&SNSR__au8SampleTime, (void*)&SNSR_cau8SampleTime, SNSR_nenNumberOfSensors );
   SNSR__u16MinuteCount = 0;
   SNSR__enSensor = SNSR_nenFirstSensor;

   LGHT_vInit();
   PRES_vInit();
}

/* Called from main wakeup task */
bool SNSR_boIncrementMinuteCount( void )
{
   /* TODO: Change from every minute to next required minute by using RTC alarms */
   SNSR__vProcessSensorPeriod();
   SNSR__u16MinuteCount++;

   APP_unRequests.F.biSensorReadRequest = 1;

   return True;
}

/* Called from main wakeup task */
bool SNSR_boProcessCurrentSensorAction( void )
{
   SNSR__vProcessCurrentSensorAction();

   return False;
}

/* ------- Application GET functions ------- */

SNSR_nenSensorList SNSR_enGetActiveSensor( void )
{
   return SNSR__enSensor;
}

uint16 SNSR_u16GetSensorMinuteCount( void )
{
   uint16 u16MinuteCount;

   /* No need for interrupt guards => Atomic operation
    * Doesnt matter anyway as all requests
    * from interrupts are queued to be
    * ran in the main task */
   u16MinuteCount = SNSR__u16MinuteCount;

   return u16MinuteCount;
}
